import type { AxiosInstance, AxiosResponse } from "axios"
import axios from "axios"
import { clone } from "lodash-es"
import { ContentTypeEnum, RequestEnum, ResultEnum } from "../../../enums/httpEnum"
import { deepMerge, setObjToUrlParams } from "../../index"
import { isString } from "../../is"
import { getAccessToken, getTenantId, setAccessToken, setRefreshToken } from "../../auth"
import { joinTimestamp, formatRequestDate } from "./helper"
import { loadingService } from "./loadingService"

// Define the Result type for AxiosResponse
type ApiResult<T = any> = {
  code: number
  data: T
  msg: string
}

export interface AxiosTransform {
  /**
   * @description: 请求之前处理配置
   */
  beforeRequestHook?: (config: CustomAxiosRequestConfig, options: RequestOptions) => CustomAxiosRequestConfig

  /**
   * @description: 请求成功处理
   */
  transformResponseHook?: (res: AxiosResponse<ApiResult>, options: RequestOptions) => any

  /**
   * @description: 请求失败处理
   */
  requestCatchHook?: (e: Error, options: RequestOptions) => Promise<any>

  /**
   * @description: 请求之前的拦截器
   */
  requestInterceptors?: (config: CustomAxiosRequestConfig, options: CreateAxiosOptions) => CustomAxiosRequestConfig

  /**
   * @description: 请求之后的拦截器
   */
  responseInterceptors?: (res: AxiosResponse<any>) => AxiosResponse<any>

  /**
   * @description: 请求之前的拦截器错误处理
   */
  requestInterceptorsCatch?: (error: Error) => void

  /**
   * @description: 请求之后的拦截器错误处理
   */
  responseInterceptorsCatch?: (axiosInstance: AxiosInstance, error: Error) => void
}

export interface CreateAxiosOptions extends CustomAxiosRequestConfig {
  authenticationScheme?: string
  urlPrefix?: string
  transform?: AxiosTransform
  requestOptions?: RequestOptions
}

export interface RequestOptions {
  // 将请求参数拼接到url
  joinParamsToUrl?: boolean
  // 格式化请求参数时间
  formatDate?: boolean
  // 是否处理请求结果
  isTransformResponse?: boolean
  // 是否返回原生响应头
  isReturnNativeResponse?: boolean
  // 是否加入url
  joinPrefix?: boolean
  // 接口地址，如果保留为空，则使用默认apiUrl
  apiUrl?: string
  // 错误消息提示类型
  errorMessageMode?: ErrorMessageMode
  // 成功消息提示类型
  successMessageMode?: ErrorMessageMode
  // 是否添加时间戳
  joinTime?: boolean
  // 忽略取消令牌
  ignoreCancelToken?: boolean
  // 是否在header中发送token
  withToken?: boolean
  // 请求重试机制
  retryRequest?: RetryRequest
}

export interface RetryRequest {
  isOpenRetry: boolean
  count: number
  waitTime: number
}

export interface Result<T = any> {
  code: number
  type: "success" | "error" | "warning"
  msg: string
  data: T
}

// Rename to avoid naming collision with axios's own AxiosRequestConfig
export interface CustomAxiosRequestConfig {
  headers?: Record<string, string | number | boolean>
  url?: string
  method?: string
  data?: any
  params?: any
  timeout?: number
  baseURL?: string
  [key: string]: any
}

// Use the renamed type in place of AxiosRequestConfig
export interface InternalAxiosRequestConfig {
  headers: Record<string, string | number | boolean>
  [key: string]: any
}

export enum ErrorMessageMode {
  NONE = "none",
  MODAL = "modal",
  MESSAGE = "message",
}

// API地址前缀
const urlPrefix = "/api"
// 租户开关
const tenantEnable = import.meta.env.VITE_TENANT_ENABLE as string

// 请求白名单，无须token的接口
const whiteList: string[] = ["/login", "/refresh-token"]

// 简单实现的token刷新请求函数，不依赖store
// @ts-ignore
async function refreshTokenRequest(refreshToken: string) {
  try {
    const response = await axios.post<any>(
      `/admin-api/system/auth/refresh-token?refreshToken=${refreshToken}`,
      {},
      {
        baseURL: import.meta.env.VITE_BASE_API_URL as string,
      }
    )
    return response.data?.data || null
  } catch (error) {
    console.error("刷新Token请求失败", error)
    return null
  }
}

/**
 * @description: 数据处理，方便区分多种处理方式
 */
const transform: AxiosTransform = {
  /**
   * @description: 处理响应数据。如果数据不是预期格式，可直接抛出错误
   */
  transformResponseHook: (res: AxiosResponse<ApiResult>, options: RequestOptions) => {
    const { isTransformResponse, isReturnNativeResponse } = options
    // 是否返回原生响应头 比如：需要获取响应头时使用该属性
    if (isReturnNativeResponse) {
      return res
    }
    // 不进行任何处理，直接返回
    if (!isTransformResponse) {
      return res.data
    }
    // 错误的时候返回
    const { data } = res
    if (!data) {
      // 显示错误消息
      loadingService.showMessage("API请求错误，未返回数据", "error")
      throw new Error("API请求错误，未返回数据")
    }
    const { code, data: result, msg } = data

    // 检查是否是401未授权错误 - 这里检查响应JSON中的code
    if (code === 401) {
      console.log("响应数据code为401，准备清理token并跳转登录页")
      // 清理token
      setAccessToken("")
      setRefreshToken("")
      localStorage.removeItem("tenantId")
      // 显示错误消息
      loadingService.showMessage("登录已过期，请重新登录", "error")
      // 跳转登录页
      window.location.replace("/login")
      throw new Error("登录已过期，请重新登录")
    }

    // 这里逻辑可以根据项目进行修改
    const hasSuccess = data && Reflect.has(data, "code") && code === ResultEnum.SUCCESS
    if (hasSuccess) {
      // 显示成功消息（如果需要）
      if (options.successMessageMode === ErrorMessageMode.MESSAGE && msg) {
        loadingService.showMessage(msg, "success")
      }
      return result
    }

    // 在此处根据自己项目的实际情况对不同的code执行不同的操作
    // 如果不希望中断当前请求，请return数据，否则直接抛出异常即可
    let errorMsg = ""
    switch (code) {
      case ResultEnum.TIMEOUT:
        errorMsg = "登录超时，请重新登录"
        // 登出处理 - 避免循环依赖
        try {
          setAccessToken("")
          // 重定向到登录页
          window.location.href = "/login"
        } catch (e) {
          console.error("处理超时错误时出现异常:", e)
        }
        break
      default:
        if (msg) {
          errorMsg = msg
        }
    }

    // errorMessageMode='modal'/'message'/'none'
    // 这里可以根据项目实际情况做处理，例如在Element Plus中显示提示
    if (options.errorMessageMode === "modal") {
      loadingService.showMessage(errorMsg || "请求出错，请稍后重试", "error")
    } else if (options.errorMessageMode === "message") {
      loadingService.showMessage(errorMsg || "请求出错，请稍后重试", "error")
    }

    throw new Error(errorMsg || "请求出错，请稍后重试")
  },

  // 请求之前处理config
  beforeRequestHook: (config, options) => {
    const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true } = options

    if (joinPrefix) {
      config.url = `${urlPrefix}${config.url}`
    }

    if (apiUrl && isString(apiUrl)) {
      config.url = `${apiUrl}${config.url}`
    }
    const params = config.params || {}
    const data = config.data || false
    formatDate && data && !isString(data) && formatRequestDate(data)
    if (config.method?.toUpperCase() === RequestEnum.GET) {
      if (!isString(params)) {
        // 给 get 请求加上时间戳参数，避免从缓存中拿数据。
        config.params = Object.assign(params || {}, joinTimestamp(joinTime, false))
      } else {
        // 兼容restful风格
        config.url = config.url + params + `${joinTimestamp(joinTime, true)}`
        config.params = undefined
      }
    } else {
      if (!isString(params)) {
        formatDate && formatRequestDate(params)
        if (Reflect.has(config, "data") && config.data && (Object.keys(config.data).length > 0 || config.data instanceof FormData)) {
          config.data = data
          config.params = params
        } else {
          // 非GET请求如果没有提供data，则将params视为data
          config.data = params
          config.params = undefined
        }
        if (joinParamsToUrl) {
          config.url = setObjToUrlParams(config.url as string, Object.assign({}, config.params, config.data))
        }
      } else {
        // 兼容restful风格
        config.url = config.url + params
        config.params = undefined
      }
    }
    return config
  },

  /**
   * @description: 请求拦截器处理
   */
  requestInterceptors: (config, options) => {
    // 是否需要设置 token
    let isToken = (config as Recordable)?.requestOptions?.withToken === false
    isToken = whiteList.some((v) => {
      if (config.url) {
        config.url.includes(v)
        return false
      }
      return true
    })

    // 请求之前处理config
    const token = getAccessToken()
    if (token && !isToken) {
      // jwt token
      const tokenType = "Bearer"
      ;(config as Recordable).headers.Authorization = options.authenticationScheme ? `${options.authenticationScheme} ${token}` : tokenType ? `${tokenType} ${token}` : token
    }

    const tenantId = getTenantId()
    if (tenantId && tenantEnable === "true") {
      ;(config as Recordable).headers["Tenant-id"] = tenantId
      localStorage.setItem("tenantId", (tenantId || "") as string)
    }

    // 添加调试信息
    console.log("请求配置:", {
      url: config.url,
      method: config.method,
      data: config.data,
      headers: (config as Recordable).headers,
    })

    return config
  },

  /**
   * @description: 响应拦截器处理
   */
  responseInterceptors: (res: AxiosResponse<any>) => {
    return res
  },

  /**
   * @description: 响应错误处理
   */
  responseInterceptorsCatch: (_axiosInstance: AxiosInstance, error: Error) => {
    const { response, code, message, config } = error as any
    const errorMessageMode = config?.requestOptions?.errorMessageMode || 'message'
    const msg: string = response?.data?.error?.message ?? ''
    const err: string = error?.toString?.() ?? ''
    let errMessage = ''

    if (axios.isCancel(error)) {
      return Promise.reject(error)
    }

    try {
      if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
        errMessage = '接口请求超时，请刷新页面重试！'
        loadingService.showMessage(errMessage, "error")
      }
      if (err?.includes('Network Error')) {
        errMessage = '网络异常，请检查您的网络连接是否正常！'
        loadingService.showMessage(errMessage, "error")
      }

      if (errMessage) {
        if (errorMessageMode === 'modal') {
          loadingService.showMessage(errMessage, "error")
        } else if (errorMessageMode === 'message') {
          loadingService.showMessage(errMessage, "error")
        }
        return Promise.reject(error)
      }
    } catch (error) {
      throw new Error(error as any)
    }

    // 处理401未授权错误 - 这里检查HTTP状态码
    if (response?.status === 401) {
      console.log("响应HTTP状态码为401，准备清理token并跳转登录页")
      // 清理token
      setAccessToken("")
      setRefreshToken("")
      localStorage.removeItem("tenantId")
      // 显示错误消息
      loadingService.showMessage("登录已过期，请重新登录", "error")
      // 跳转登录页
      window.location.replace("/login")
    }

    loadingService.showMessage(msg || errMessage || '请求出错，请稍后重试', "error")

    return Promise.reject(error)
  },
}

export class VAxios {
  private axiosInstance: AxiosInstance
  private readonly options: CreateAxiosOptions

  constructor(options: CreateAxiosOptions) {
    this.options = options
    this.axiosInstance = axios.create(options)
    this.setupInterceptors()
  }

  /**
   * @description:  创建axios实例
   */
  private createAxios(config: CreateAxiosOptions): void {
    this.axiosInstance = axios.create(config)
  }

  private getTransform() {
    const { transform } = this.options
    return transform
  }

  getAxios(): AxiosInstance {
    return this.axiosInstance
  }

  /**
   * @description: 重新配置axios
   */
  configAxios(config: CreateAxiosOptions) {
    if (!this.axiosInstance) {
      return
    }
    this.createAxios(config)
  }

  /**
   * @description: 设置通用header
   */
  setHeader(headers: any): void {
    if (!this.axiosInstance) {
      return
    }
    Object.assign(this.axiosInstance.defaults.headers, headers)
  }

  /**
   * @description: 拦截器配置
   */
  private setupInterceptors() {
    const transform = this.getTransform()
    if (!transform) {
      return
    }
    const {
      requestInterceptors,
      requestInterceptorsCatch,
      responseInterceptors,
      responseInterceptorsCatch,
    } = transform

    // 处理请求拦截器
    this.axiosInstance.interceptors.request.use((config: any) => {
      // 显示loading
      loadingService.show()

      // 请求拦截器配置
      if (requestInterceptors) {
        config = requestInterceptors(config as CustomAxiosRequestConfig, this.options)
      }
      return config
    }, undefined)

    // 请求拦截器错误捕获
    requestInterceptorsCatch &&
      this.axiosInstance.interceptors.request.use(undefined, (error) => {
        // 隐藏loading
        loadingService.hide()
        return requestInterceptorsCatch(error)
      })

    // 响应拦截器配置
    this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
      // 隐藏loading
      loadingService.hide()

      if (responseInterceptors) {
        res = responseInterceptors(res)
      }
      return res
    }, undefined)

    // 响应拦截器错误捕获
    responseInterceptorsCatch &&
      this.axiosInstance.interceptors.response.use(undefined, (error) => {
        // 隐藏loading
        loadingService.hide()
        return responseInterceptorsCatch(this.axiosInstance, error)
      })
  }

  get<T = any>(config: CustomAxiosRequestConfig, options?: RequestOptions): Promise<T> {
    return this.request({ ...config, method: "GET" }, options)
  }

  post<T = any>(config: CustomAxiosRequestConfig, options?: RequestOptions): Promise<T> {
    return this.request({ ...config, method: "POST" }, options)
  }

  put<T = any>(config: CustomAxiosRequestConfig, options?: RequestOptions): Promise<T> {
    return this.request({ ...config, method: "PUT" }, options)
  }

  delete<T = any>(config: CustomAxiosRequestConfig, options?: RequestOptions): Promise<T> {
    return this.request({ ...config, method: "DELETE" }, options)
  }

  request<T = any>(config: CustomAxiosRequestConfig, options?: RequestOptions): Promise<T> {
    let conf: CreateAxiosOptions = clone(config)
    const transform = this.getTransform()

    const { requestOptions } = this.options

    const opt: RequestOptions = Object.assign({}, requestOptions, options)

    const { beforeRequestHook, requestCatchHook, transformResponseHook } = transform || {}
    if (beforeRequestHook) {
      conf = beforeRequestHook(conf, opt)
    }
    conf.requestOptions = opt

    return new Promise((resolve, reject) => {
      this.axiosInstance
        .request<any, AxiosResponse<ApiResult>>(conf)
        .then((res: AxiosResponse<ApiResult>) => {
          if (transformResponseHook) {
            try {
              const ret = transformResponseHook(res, opt)
              resolve(ret)
            } catch (err) {
              reject(err || new Error("request error!"))
            }
            return
          }
          resolve(res as unknown as Promise<T>)
        })
        .catch((e: Error) => {
          if (requestCatchHook) {
            reject(requestCatchHook(e, opt))
            return
          }
          reject(e)
        })
    })
  }
}

/**
 * @description: axios创建配置
 */
export function createAxios(opt?: Partial<CreateAxiosOptions>) {
  return new VAxios(
    deepMerge(
      {
        // 认证方案
        authenticationScheme: "Bearer",
        timeout: 60 * 1000,
        // 基础url
        baseURL: import.meta.env.VITE_BASE_API_URL as string,
        headers: { "Content-Type": ContentTypeEnum.JSON },
        // 如果是form-data格式
        // headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
        // 数据处理方式
        transform,
        // 配置项
        requestOptions: {
          // 默认将prefix 添加到url
          joinPrefix: true,
          // 是否返回原生响应头 比如：需要获取响应头时使用该属性
          isReturnNativeResponse: false,
          // 需要对返回数据进行处理
          isTransformResponse: true,
          // post请求的时候添加参数到url
          joinParamsToUrl: false,
          // 格式化提交参数时间
          formatDate: true,
          // 消息提示类型
          errorMessageMode: "message",
          // 接口地址
          apiUrl: import.meta.env.VITE_BASE_API_URL as string,
          // 接口拼接地址
          urlPrefix: urlPrefix,
          //  是否加入时间戳
          joinTime: true,
          // 忽略重复请求
          ignoreCancelToken: true,
          // 是否携带token
          withToken: true,
          retryRequest: {
            isOpenRetry: true,
            count: 3,
            waitTime: 100,
          },
        },
      },
      opt || {}
    )
  )
}

export const defHttp = createAxios()

// 在文件顶部声明类型
declare global {
  interface Window {
    __refreshTokenPromise: Promise<any> | null
    automation: {
      start: (data: any) => Promise<{ success: boolean }>
      stop: () => Promise<{ success: boolean; isRunning: boolean }>
    }
    ipcRenderer: Electron.IpcRenderer
  }
}
